package edu.purdue.cs.cs505._final.server.client;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Iterator;

import edu.purdue.cs.cs505._final.server.GetShareStore;
import edu.purdue.cs.cs505._final.server.ReceiveSharing;
import edu.purdue.cs.cs505._final.server.ServerStub;
import edu.purdue.cs.cs505._final.server.WSParentIndex;
import edu.purdue.cs.cs505._final.server.WSShare;
import edu.purdue.cs.ds.ServerSets;
import edu.purdue.cs.ds.vss.Constants;
import edu.purdue.cs.ds.vss.Generator;
import edu.purdue.cs.ds.vss.IndexSets;
import edu.purdue.cs.ds.vss.ParentIndex;
import edu.purdue.cs.ds.vss.Reconstructor;
import edu.purdue.cs.ds.vss.Share;
import edu.purdue.cs.ds.vss.ShareStore;
import edu.purdue.cs.ds.vss.VerifiableSharing;

public class Dealer {

	public static void main(String[] args) throws Exception {
		//Generate server sets
		int n = 3;
		int k = 1;

		ServerSets serverSets = new ServerSets(n, k);
		int l = serverSets.getL();
		ArrayList<ArrayList<Integer>> sets = serverSets.constructServerSets();
		
		System.out.println("l : " + l);
		SecureRandom sr = new SecureRandom();
		BigInteger r =  new BigInteger(Constants.q.bitLength() - 1, sr);
		BigInteger s =  new BigInteger(Constants.q.bitLength() - 1, sr);

		System.out.println("Main secret " + s);
		
		Generator g = new Generator(s, r , l);
		VerifiableSharing vs = g.generateVerifiableSharing();
		ArrayList<BigInteger> shares = vs.getS();
		
		ArrayList<Share> shareList = new ArrayList<Share>();
		ParentIndex parentIndex = new ParentIndex(0, 0, null);
		for(int i = 0; i < shares.size(); i ++) {
			shareList.add(new Share(shares.get(i), i, parentIndex));
		}
		
		IndexSets is = new IndexSets();
		ArrayList<ArrayList<Share>> serverShares = is.generateShareSets2(n, shareList, sets);
		
		//To verify
		ArrayList<ShareStore> _stores = new ArrayList<ShareStore>();
		for(int i = 0; i < n; i++) {
			_stores.add(new ShareStore());
		}		
		for(int i = 0; i < n; i ++) {
			ShareStore st = _stores.get(i);
			ArrayList<Share> tmpSh = serverShares.get(i);
			for (Iterator<Share> iterator = tmpSh.iterator(); iterator.hasNext();) {
				Share tmp = iterator.next();
				st.update(tmp);
			}
		}
//		System.out.println(_stores);
		Reconstructor reconstructor = new Reconstructor();
		BigInteger s2 = reconstructor.reconstructSecretFromStores(_stores, n, k);
		System.out.println(s2);
		System.out.println("First reconstruction : " + s.equals(s2));
		
		
		//Store the server shares in each sharestore
		for(int i = 0; i < n; i ++) {
			ArrayList<Share> tmpSh = serverShares.get(i);
			ServerStub stub = new ServerStub("http://localhost:8080/axis2/services/server" + (i));
			System.out.println("Server " + (i+1));
			for (Iterator<Share> iterator = tmpSh.iterator(); iterator.hasNext();) {
				Share tmp = iterator.next();

				System.out.println(tmp);
				
				WSParentIndex pi = new WSParentIndex();
				pi.setIndex(0);
				pi.setServer(0);
				
				WSShare wss = new WSShare();
				wss.setParentIndex(pi);
				wss.setIndex(tmp.getIndex());
				wss.setShareValue(tmp.getS().toString());
				
				ReceiveSharing sharingInput = new ReceiveSharing();
				sharingInput.setReceiveSharing(wss);
				stub.receiveSharing(sharingInput);
				
				
			}
		}

		ArrayList<ShareStore> stores = new ArrayList<ShareStore>();
		for(int i = 0; i < n; i ++) {
			ServerStub stub = new ServerStub("http://localhost:8080/axis2/services/server" + (i));
			System.out.println("Server " + (i+1));
			GetShareStore anyValue = new GetShareStore();
			anyValue.setIn("");
			String storeStr = stub.getShareStore(anyValue).getOut();
			
			ShareStore store = new ShareStore(storeStr);
			stores.add(store);
			
//			System.out.println(store);
		}
		
		
		System.out.println("Stores match : " + _stores.equals(stores));
		
		Reconstructor recon = new Reconstructor();
		
		BigInteger tmpS = recon.reconstructSecretFromStores(stores, n, k);
		System.out.println(tmpS);
		System.out.println(tmpS.equals(s));
	}
}
